package com.blockmeta.bbs.businesslibrary.websocket;

import androidx.annotation.NonNull;
import com.blankj.utilcode.util.LogUtils;

import com.blockmeta.bbs.baselibrary.base.app.BaseApp;
import com.blockmeta.bbs.baselibrary.utils.SecurityUtil;
import com.blockmeta.bbs.baselibrary.utils.SharedPreferenceUtil;
import com.blockmeta.bbs.baselibrary.utils.gson.GsonUtil;
import com.blockmeta.bbs.businesslibrary.business.DataManager;
import com.blockmeta.bbs.businesslibrary.constant.Constant;
import com.blockmeta.bbs.businesslibrary.net.callback.CommonWebCallback;
import com.blockmeta.bbs.businesslibrary.net.retrofit.RestManager;
import com.blockmeta.bbs.businesslibrary.net.retrofit.api.InterfaceQuote;
import com.blockmeta.bbs.businesslibrary.pojo.CoinsDetailPOJO;
import com.blockmeta.bbs.businesslibrary.pojo.ExchangeF10POJO;
import com.blockmeta.bbs.businesslibrary.pojo.HomeRankListPOJO;
import com.blockmeta.bbs.businesslibrary.pojo.websocket.GetQuotePOJO;
import com.blockmeta.bbs.businesslibrary.pojo.websocket.GetTradePOJO;
import com.blockmeta.bbs.businesslibrary.pojo.websocket.UnSubscribeQuotePOJO;
import com.blockmeta.bbs.businesslibrary.pojo.websocket.UnSubscribeTradePOJO;
import com.blockmeta.bbs.businesslibrary.widget.chartview.ChartData;

import org.greenrobot.eventbus.Subscribe;
import org.json.JSONException;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.concurrent.CopyOnWriteArraySet;
import java.util.concurrent.locks.ReentrantReadWriteLock;

import buf.NotifyOuterClass;
import buf.Return;
import retrofit2.Call;
import retrofit2.Retrofit;

import static com.blockmeta.bbs.businesslibrary.constant.Constant.MICRO_APP;


public class QuoteCenter extends BaseCenter implements IFlowManager {

    protected HashMap<String, Market> m_mapMarket;            // <MarketCode, Market>
    private ReentrantReadWriteLock m_lockTickTable;
    public static final String EXCHANGE = "exchange";
    public static final String SYMBOL = "symbol";
    public static final String TICKER = "ticker";
    public static final String TRADE = "trade";
    public static final String UNSUBSCRIBE = "unsubscribe";
    public static final String SUBSCRIBE = "subscribe";
    protected CopyOnWriteArraySet<String> m_subscibeStatus;


    public QuoteCenter() {
        super();
        m_lockTickTable = new ReentrantReadWriteLock();
        m_mapMarket = new HashMap<String, Market>();
        m_subscibeStatus = new CopyOnWriteArraySet<>();
    }

    @Override
    public void onCreate() {

    }


    @Override
    public void onConnectCreate() {
        if (!ConnectCenter.getConnectCenter().isRegistered(this)) {
            ConnectCenter.getConnectCenter().register(this);
        }
    }


    // 查詢線圖及訂閱
    public ChartData queryChart(String key, String symbolCode, ChartData.ChartPeroid type) {

        Symbol symbol = getSymbol(symbolCode);
        if (symbol == null)
            return null;

        return symbol.queryChart(key, type);
    }

    public boolean getConnectOK(Symbol symbol) {

        ConnectManager connectManager = ConnectCenter.getConnectCenter().getConnectManager(symbol.getMarket());
        if (connectManager == null || !connectManager.isConnectOK())
            return false;
        return true;


    }

    /**
     * p批量订阅和解除订阅，目前只有单个
     *
     * @param arRegSymbols
     * @param arUnRegSymbols
     */
    public void queryQuote(ArrayList<String> arRegSymbols, ArrayList<String> arUnRegSymbols) {
        if (arRegSymbols != null && arRegSymbols.size() > 0) {
            Symbol symbol = getSymbol(arRegSymbols.get(0));
            ConnectManager connectManager = ConnectCenter.getConnectCenter().getConnectManager(symbol.getMarket());
            if (connectManager == null)
                return;

            GetQuotePOJO pkt = new GetQuotePOJO();
            pkt.set_pt("subscribe_ticker");
            pkt.setExchange(symbol.getExchange());
            pkt.setSymbol(symbol.getSymbolCode());
            pkt.set_seq(ConnectManager.getSeqNo());

            connectManager.write(pkt);

        }
        if (arUnRegSymbols != null && arUnRegSymbols.size() > 0) {

            Symbol symbol = getSymbol(arUnRegSymbols.get(0));
            ConnectManager connectManager = ConnectCenter.getConnectCenter().getConnectManager(symbol.getMarket());
            if (connectManager == null)
                return;

            UnSubscribeQuotePOJO pkt = new UnSubscribeQuotePOJO();
            pkt.set_pt("unsubscribe_ticker");
            pkt.setExchange(symbol.getExchange());
            pkt.setSymbol(symbol.getSymbolCode());
            pkt.set_seq(ConnectManager.getSeqNo());

            connectManager.write(pkt);

        }

    }

    /**
     * p批量订阅和解除订阅，目前只有单个
     *
     * @param arRegSymbols
     * @param arUnRegSymbols
     */
    public void subscribeTrade(ArrayList<String> arRegSymbols, ArrayList<String> arUnRegSymbols) {
        if (arRegSymbols != null && arRegSymbols.size() > 0) {
            Symbol symbol = getSymbol(arRegSymbols.get(0));
            ConnectManager connectManager = ConnectCenter.getConnectCenter().getConnectManager(symbol.getMarket());
            if (connectManager == null)
                return;

            GetTradePOJO pkt = new GetTradePOJO();
            pkt.set_pt("subscribe_trade");
            pkt.setExchange(symbol.getExchange());
            pkt.setSymbol(symbol.getSymbolCode());
            pkt.set_seq(ConnectManager.getSeqNo());

            connectManager.write(pkt);
        }
        if (arUnRegSymbols != null && arUnRegSymbols.size() > 0) {

            Symbol symbol = getSymbol(arUnRegSymbols.get(0));
            ConnectManager connectManager = ConnectCenter.getConnectCenter().getConnectManager(symbol.getMarket());
            if (connectManager == null)
                return;

            UnSubscribeTradePOJO pkt = new UnSubscribeTradePOJO();
            pkt.set_pt("unsubscribe_trade");
            pkt.setExchange(symbol.getExchange());
            pkt.setSymbol(symbol.getSymbolCode());
            pkt.set_seq(ConnectManager.getSeqNo());

            connectManager.write(pkt);
        }
    }

    public void unregisterChart(String key, String symbolCode, ChartData.ChartPeroid type) {
        Symbol symbol = getSymbol(symbolCode);
        if (symbol != null) {
            symbol.unregisterChart(key, type);
        }
    }

    /**
     * 币种F10网络请求
     *
     * @param name
     */
    public void queryF10(String name,String fullName) {
        Retrofit retrofit = RestManager.getRetrofit();

        InterfaceQuote quote = retrofit.create(InterfaceQuote.class);
        Call<String> call = null;
        String url = MICRO_APP + "/ranking/detail/"+name+"?full_name="+fullName;
        String token = SharedPreferenceUtil.getString(BaseApp.getApp(), Constant.TOKEN,"");
        String time = String.valueOf(System.currentTimeMillis()/1000);
        LogUtils.d("xxx", "queryF10: "+url);
        String sign = SecurityUtil.MD5(url+token+time);
        call = quote.getRank(name,fullName,sign,time);

        call.enqueue(new CommonWebCallback<String>("getRank") {

            @Override
            public void onSuccess(String response) {

                try {
                    org.json.JSONObject jsonObject = new org.json.JSONObject(response);
                    HomeRankListPOJO.ListBean listBean = GsonUtil.buildGson().fromJson(jsonObject.getJSONObject("ranking").toString(), HomeRankListPOJO.ListBean.class);
                    if (listBean != null) {
                        post(new Event_RankDetail(listBean));
                    } else {
                        post(new Event_RankDetail(null));
                    }
                } catch (JSONException e) {
                    e.printStackTrace();
                    post(new Event_RankDetail(null));
                }

            }

            @Override
            public void onError(Throwable t) {
                post(new Event_RankDetail(null));
            }
        });
    }

    /**
     * 交易所F10网络请求
     *
     * @param name
     */

    public void queryExchangeF10(String name)
    {
        Retrofit retrofit = RestManager.getRetrofit();

        InterfaceQuote quote = retrofit.create(InterfaceQuote.class);
        Call<String> call = null;
        String url = MICRO_APP + "/exchange/"+name;
        String token = SharedPreferenceUtil.getString(BaseApp.getApp(), Constant.TOKEN,"");
        String time = String.valueOf(System.currentTimeMillis()/1000);
        String sign = SecurityUtil.MD5(url+token+time);
        LogUtils.d("xxx", "queryExchangeF10: "+url);
        call = quote.getExchange(name,sign,time);

        call.enqueue(new CommonWebCallback<String>("getExchange") {

            @Override
            public void onSuccess(String response) {

                try {
                    ExchangeF10POJO exchangeF10POJO = GsonUtil.buildGson().fromJson(response, ExchangeF10POJO.class);
                    if(exchangeF10POJO != null) {
                        post(new EventExchangeF10(exchangeF10POJO));
                    }
                    else
                    {
                        post(new EventExchangeF10(null));
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                    post(new EventExchangeF10(null));
                }

            }

            @Override
            public void onError(Throwable t) {
                post(new EventExchangeF10(null));
            }
        });
    }
    //
//	public void unregisterChart(String key, String symbolCode, ChartPeroid type)
//	{
//		Symbol symbol = getSymbol(symbolCode);
//		if (symbol != null)
//		{
////			symbol.unregisterChart(type);
//			symbol.unregisterChart2(key, type);
//		}
//	}

    @Override
    public void processPacket(Return.NormalReturn packet, ConnectManager connectManager) {
        processPacket(packet.getExtraMap(), packet);
    }

    protected void processPacket(Map<String, String> map, Return.NormalReturn packet) {
        if (map.get("symbol") == null || map.get("exchange") == null) {return;}
        if("notify_res".equals(packet.getEvent())){
            processNotifyPacket(packet);
            return;
        }

        Symbol symbol = this.getSymbol(Symbol.makeSymbolCode(map.get("symbol"), map.get("exchange")));

        if (symbol != null) {
            switch (packet.getEvent()) {
                case "kline_list":
                    symbol.processChartUpdate(packet);
                    break;
                case "trade_list":
                    symbol.processTradeUpdate(packet);
                    break;
                case "tickers":
                    symbol.processQuoteUpdate(packet);
                    break;
                case "depth":
                    symbol.processDepthUpdate(packet);
                    break;
                default:
                    break;
            }
        }
    }


    /**
     * 取得Market物件
     *
     * @param strMarketCode MarketCode, Ex: "FX"
     * @return
     */
    public synchronized Market getMarket(String strMarketCode) {
        Market market = m_mapMarket.get(strMarketCode);

        if (market == null) {
            market = new Market(strMarketCode);
            m_mapMarket.put(strMarketCode, market);
        }

        return market;
    }

    public Symbol getSymbol(String strSymbolCode) // strSymbolCode:
    // SymbolID.MarketID
    {
        String marketCode = "coin";//QuoteCenter.getMarektCode(strSymbolCode);

        if (marketCode != null) {
            Market market = getMarket(marketCode);
            if (market != null) {
                return market.getSymbol(strSymbolCode);
            }
        }
        return null;
    }

    public static String getCode(String symbolCode) {
        int dot = symbolCode.indexOf('.');

        if (dot != -1) {
            return symbolCode.substring(0, dot);
        }
        return symbolCode;
    }

    public static String getMarektCode(String symbolCode) {
        int dot = symbolCode.lastIndexOf('.');

        if (dot != -1) {
            return symbolCode.substring(dot + 1);
        }
        return null;
    }

    @Subscribe
    public void onEvent(ConnectManager.Event_ConnectOK event) {
        if (event.m_market == null) {
            return;
        }

        event.m_market.onConnectOK();

        recoverSubscribeStatus();
//		getQuoteTickTable(event.m_market.getCode()).getTickTable();
    }

    private void recoverSubscribeStatus() {
        ArrayList<String> arRegQuoteSymbols = new ArrayList<String>();
        ArrayList<String> arRegTradeSymbols = new ArrayList<String>();

        Iterator<String> iterator = m_subscibeStatus.iterator();
        while (iterator.hasNext()){
            String code = iterator.next();
            if(code.endsWith(TICKER)){
                arRegQuoteSymbols.add(code.replace("$".concat(TICKER), ""));
            }else if(code.endsWith(TRADE)){
                arRegTradeSymbols.add(code.replace("$".concat(TRADE), ""));
            }
        }

        DataManager.getDataManager().getQuoteCenter().queryQuote(arRegQuoteSymbols,
                null);
        DataManager.getDataManager().getQuoteCenter().subscribeTrade(arRegTradeSymbols,
                null);
    }

    // 斷線的處理
    @Subscribe
    public void onEvent(ConnectManager.Event_ConnectClose event) {
        for (Market market : m_mapMarket.values()) {
            market.onConnectClose();
        }
    }

    /**
     * 行情更新
     *
     * @author CCMa
     */
    public static class Event_MemoryRefresh {
        public Symbol m_symbol;
        public CoinsDetailPOJO m_pkt;

        Event_MemoryRefresh(Symbol symbol, CoinsDetailPOJO pkt) {
            m_symbol = symbol;
            m_pkt = pkt;
        }
    }

    public static class Event_DeepQuotePercent {
        public Symbol m_symbol;
        public float m_percent;

        public Event_DeepQuotePercent(Symbol symbol, float percent) {
            m_symbol = symbol;
            m_percent = percent;
        }
    }


    public static class Event_RankDetail {
        public HomeRankListPOJO.ListBean m_pkt;

        Event_RankDetail(HomeRankListPOJO.ListBean pkt) {
            m_pkt = pkt;
        }
    }

    public static class EventExchangeF10{
        public ExchangeF10POJO mF10POJO;

        EventExchangeF10(ExchangeF10POJO f10POJO){
            mF10POJO = f10POJO;
        }
    }

//	/**
//	 * 行情更新
//	 * @author websocket
//	 *
//	 */
//	public static class Event_MemoryRefresh
//	{
//        public Market m_market;
//		public Symbol m_symbol;
//		public Set<Integer> m_FieldID;
//		public QuoteUpdatePacket m_pkt;
//
//		Event_MemoryRefresh(Symbol symbol, Set<Integer> fieldid, QuoteUpdatePacket pkt)
//		{
//			m_symbol = symbol;
//			m_FieldID = fieldid;
//			m_pkt = pkt;
//		}
//	}


    public void clear() {

    }

    private void processNotifyPacket(Return.NormalReturn packet) {
        Map<String, String> extraMap = packet.getExtraMap();
        NotifyOuterClass.Notify notify = packet.getNotify();
        if(extraMap != null && extraMap.containsKey(EXCHANGE) && extraMap.containsKey(SYMBOL)) {
            String exchange = extraMap.get(EXCHANGE);
            String symbol = extraMap.get(SYMBOL);
            switch (notify.getType()) {
                case TICKER:
                    if(SUBSCRIBE.equals(notify.getMsg())){
                        m_subscibeStatus.add(getUniqueSymbol(exchange, symbol, TICKER));
                    }else if(UNSUBSCRIBE.equals(notify.getMsg())){
                        m_subscibeStatus.remove(getUniqueSymbol(exchange, symbol, TICKER));
                    }
                    break;
                case TRADE:
                    if(SUBSCRIBE.equals(notify.getMsg())){
                        m_subscibeStatus.add(getUniqueSymbol(exchange, symbol, TRADE));
                    }else if(UNSUBSCRIBE.equals(notify.getMsg())){
                        m_subscibeStatus.remove(getUniqueSymbol(exchange, symbol, TRADE));
                    }
                    break;
                default:
                    break;
            }
        }
    }

    @NonNull
    private String getUniqueSymbol(String exchange, String symbol, String type) {
        return Symbol.makeSymbolCode(symbol, exchange).concat("$").concat(type);
    }


}
